package com.leetcode.study.interview;

import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicStampedReference;

/**
 * 使用AtomicStampedReference解决ABA问题 <br/>
 * 为了解决上述的ABA问题，Java提供了两种带版本戳的原子引用类型：
 * AtomicStampedReference：带版本戳的原子引用类型，版本戳为int类型。 <br/>
 * AtomicMarkableReference：带版本戳的原子引用类型，版本戳为boolean类型。 <br/>
 *
 *
 */
public class ABATest {

    public static void main(String[] args) {


        // ABA问题
        //System.out.println("==========ABA问题：");
        //AtomicReference<String> reference = new AtomicReference<>("A");
        //new Thread(() -> {
        //    //获取期望值
        //    String expect = reference.get();
        //    //打印期望值
        //    System.out.println(Thread.currentThread().getName() + "---- expect: " + expect);
        //    try {
        //        //干点别的事情
        //        Thread.sleep(20);
        //    } catch (InterruptedException e) {
        //        e.printStackTrace();
        //    }
        //    //打印实际值
        //    System.out.println(Thread.currentThread().getName() + "---- actual: " + reference.get());
        //    //进行CAS操作
        //    boolean result = reference.compareAndSet("A", "X");
        //    //打印操作结果
        //    System.out.println(Thread.currentThread().getName() + "---- result: " + result + " ==》 final reference = " + reference.get());
        //}).start();
        //
        //new Thread(() -> {
        //    try {
        //        Thread.sleep(5);
        //    } catch (InterruptedException e) {
        //        e.printStackTrace();
        //    }
        //    //进行ABA操作
        //    System.out.print(Thread.currentThread().getName() + "---- change: " + reference.get());
        //    reference.compareAndSet("A", "B");
        //    System.out.print(" -- > B");
        //    reference.compareAndSet("B", "A");
        //    System.out.println(" -- > A");
        //    System.out.println("这个A已经是我从A改成了B，然后又从B改成了A， 来产生ABA问题了，哈哈~， 要是修改成了X就是有问题了");
        //}).start();


        //通过版本戳解决ABA问题
        System.out.println("\n==========通过版本戳解决ABA问题：");
        AtomicStampedReference<String> stampedRef = new AtomicStampedReference<>("A", 1);
        new Thread(() -> {
            //获取期望值
            String expect = stampedRef.getReference();
            //获取期望版本戳
            Integer stamp = stampedRef.getStamp();
            //打印期望值和期望版本戳
            System.out.println(Thread.currentThread().getName() + "---- expect: " + expect + " 版本号：" + stamp);
            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //打印实际值和实际版本戳
            System.out.println(Thread.currentThread().getName() + "---- actual: " + stampedRef.getReference() + " 实际版本号：" + stampedRef.getStamp());
            //进行CAS操作（带版本戳）
            boolean result = stampedRef.compareAndSet("A", "X", stamp, stamp + 1);
            //打印操作结果
            System.out.println(Thread.currentThread().getName() + "---- result: " + result + " ==》 final reference = " + stampedRef.getReference() + " 版本号：" + stampedRef.getStamp());
        }).start();

        new Thread(() -> {
            try {
                Thread.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 进行ABA操作（带版本戳）
            System.out.print(Thread.currentThread().getName() + "---- change: " + stampedRef.getReference() + " 版本号：" + stampedRef.getStamp());
            stampedRef.compareAndSet("A", "B", stampedRef.getStamp(), stampedRef.getStamp() + 1);
            System.out.print(" -- > B" + " 版本号：" + stampedRef.getStamp());
            stampedRef.compareAndSet("B", "A", stampedRef.getStamp(), stampedRef.getStamp() + 1);
            System.out.println(" -- > A" + " 版本号：" + stampedRef.getStamp());
        }).start();


    }


}
